#ifndef MSG_H
#define MSG_H
#include <sys/ipc.h>
#include <sys/msg.h>
#include "testbase.h"

/*
    ipcs -q 查看
    ipcrm -q <id> 删除id队列
    ipcrm -a 删除全部
*/

// ./exe rsd

class Msg : public TestBase {
    struct my_msg {
        long type;
        char data[1024];
    };

    enum : int {
        RECV = 0x01,
        SEND = 0x02,
        DEL = 0x04
    };

    int parse() {
        int cmd = 0;
        if(argc_ > 1) {
            const std::string str = argv_[1];
            for(const auto& ch : str) {
                if(ch == 'R' || ch == 'r') cmd |= RECV;
                else if(ch == 'S' || ch == 's') cmd |= SEND;
                else if(ch == 'D' || ch == 'd') cmd |= DEL;
            }
        }
        return cmd;
    }

public:
    Msg(int argc, char** argv) : TestBase(argc, argv), cmd(parse()) {
        memset(&sendmsg, 0, sizeof(my_msg));
        memset(&recvmsg, 0, sizeof(my_msg));

        key_t key = ftok("/temp", 1);
        msgId = msgget(key, IPC_CREAT | 0777);
        valid = msgId!=-1;
        if(valid) puts("msgget succeed");
        else puts("msgget failed");
    }

    ~Msg() {
        if(!valid || !(cmd&DEL)) return;
        int ret = msgctl(msgId, IPC_RMID, nullptr);
        if(ret == 0) puts("msgctl succeed");
        else puts("msgctl failed");
    }

    bool recv(int type) {
        int len = msgrcv(msgId, &recvmsg, sizeof(recvmsg.data), type, IPC_NOWAIT);
        if(len > 0) cout <<  "recv : " << len << ", data:" << recvmsg.data <<  endl;
        else cout << "recv fail, type:" << recvmsg.type << endl;
        return len > 0;
    }

    bool send(int type) {
        sendmsg.type = type;
        sprintf(sendmsg.data, "msg type : %ld",  sendmsg.type);
        int len = strlen(sendmsg.data)+1;
        int ret = msgsnd(msgId, &sendmsg, len, sendmsg.type); // 0 or -1
        if(ret) cout << "send fail, " << strerror(errno) << endl; //
        else puts("send succeed");
        return !ret;
    }

    void test() override {
        if(!valid) {
            puts("test fail");
            return;
        }
        if(cmd&SEND) send(512);
        if(cmd&RECV) recv(512);
    }

private:
    int  msgId;
    bool valid;
    my_msg sendmsg, recvmsg;
    const int cmd; //
};


#endif // MSG_H
